package eu.boss.activities;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;

import Util.Util;
import android.app.AlertDialog;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.os.AsyncTask.Status;
import android.os.Bundle;
import android.os.IBinder;
import android.support.v4.app.Fragment;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.widget.Toast;

import com.actionbarsherlock.app.SherlockFragmentActivity;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;
import com.actionbarsherlock.view.SubMenu;
import com.actionbarsherlock.view.Window;

import eu.boss.R;
import eu.boss.controller.ShadowStatsController;
import eu.boss.exceptions.ServerErrorException;
import eu.boss.fragments.GameFragment;
import eu.boss.fragments.MyPagerAdapter;
import eu.boss.fragments.StatsFragment;
import eu.boss.fragments.TeamStatsFragment;
import eu.boss.http.Http;
import eu.boss.model.LoginResponseMessage;
import eu.boss.model.Player;
import eu.boss.model.TeamType;

/**
 * This class links all fragments and makes 
 * @author Arnaud
 *
 */
public class FragmentsSliderActivity extends SherlockFragmentActivity {

	private static int NEW_PLAYER_ID = 131073; //I don't know why. Maybe because the activity is thrown from the fragment
	private static int UPDATE_STATS_ID = 3;	
	private PagerAdapter mPagerAdapter;
	private ViewPager mPager;
	private ShadowStatsController mController;
	private ObjectMapper mMapper = new ObjectMapper();
	PlayersPutTask mPutTask;
	PlayersListRefreshTask mRefreshTask;
	
	List<Fragment> mFragments;
	
	private ServiceConnection mControllerConnection = new ServiceConnection() {
		// Called when the connection with the service is established
		public void onServiceConnected(ComponentName className, IBinder service) {
			mController = ((ShadowStatsController.LocalBinder) service)
					.getService();
			initiateFragments();
		}

		// Called when the connection with the service disconnects unexpectedly
		public void onServiceDisconnected(ComponentName className) {
			mController = null;
		}
	};
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {	
		requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
		super.onCreate(savedInstanceState);
		super.setContentView(R.layout.viewpager);	
		
		setSupportProgressBarIndeterminateVisibility(false);
	}
	
	
	/**
	 * Change menu with the paging
	 */
	@Override
    public boolean onCreateOptionsMenu(Menu menu) {
		if (mPager.getCurrentItem()==0)
		{//teams stats page
			menu.add(getString(R.string.refresh))
            .setIcon(R.drawable.ic_refresh)
            .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
		}
		
		if (mPager.getCurrentItem()==1)
		{//individual stats page
			menu.add(getString(R.string.refresh))
            .setIcon(R.drawable.ic_refresh)
            .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
			
			SubMenu sub = menu.addSubMenu(getString(R.string.menu));
	        sub.add(0, 0, 0, getString(R.string.init_scores));
	        sub.add(0, 1, 0, getString(R.string.delete_players));
	        sub.add(0, 2, 0, getString(R.string.disconnect));
	        sub.getItem().setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
		}
		else if (mPager.getCurrentItem()==2)
		{//new game page
			menu.add(getString(R.string.plus))
            .setIcon(R.drawable.ic_plus)
            .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
		}
			
        return true;
    }
	
	
	/**
	 * Callback method when an actionbar's option item is selected 
	 */
	  @Override
	    public boolean onOptionsItemSelected(MenuItem item) {
	        //This uses the imported MenuItem from ActionBarSherlock
		  
		  	if (item.getTitle().toString().compareTo(getString(R.string.refresh))==0)
		  		updatePlayerList();
		  	else if (item.getTitle().toString().compareTo(getString(R.string.plus))==0)	
		  		startActivityForResult(new Intent(FragmentsSliderActivity.this, UpdateStatsActivity.class), UPDATE_STATS_ID);
		  	
		  	else if (item.getTitle().toString().compareTo(getTitle().toString())==0)
		  		startActivity(new Intent (FragmentsSliderActivity.this, AboutActivity.class));
		  	
		  	else if (item.getTitle().toString().compareTo(getString(R.string.init_scores))==0)
		  	{
		  		AlertDialog.Builder adb = new AlertDialog.Builder(this);
				adb.setTitle(getString(R.string.init_scores));
				adb.setMessage(getString(R.string.are_you_sure));						
				adb.setPositiveButton("Ok",
						new DialogInterface.OnClickListener() {

							public void onClick(DialogInterface dialog, int which) {
								mController.getPlayersList().reinitList();
								mController.getTeamList().reinitList();
						  		StatsFragment fragment = (StatsFragment) mFragments.get(1);			
								fragment.updateList();
								updateServer();	
							}
						});
				adb.setNegativeButton("Annuler", null);
				adb.show();   			
		  			  		
		  	}
		  	
		  	else if (item.getTitle().toString().compareTo(getString(R.string.delete_players))==0)
		  	{		  		
		  		AlertDialog.Builder adb = new AlertDialog.Builder(this);
				adb.setTitle(getString(R.string.delete_players));
				adb.setMessage(getString(R.string.are_you_sure));					
				adb.setPositiveButton("Ok",
						new DialogInterface.OnClickListener() {

							public void onClick(DialogInterface dialog,	int which) {
								mController.getPlayersList().deletePlayers();	
								StatsFragment fragment = (StatsFragment) mFragments.get(1);	
								fragment.updateList();
								updateServer();
							}
						});
				
				adb.setNegativeButton("Annuler", null);
				adb.show();   
				
		  	}
		  	else if (item.getTitle().toString().compareTo(getString(R.string.disconnect))==0)
		  	{
		  		AlertDialog.Builder adb = new AlertDialog.Builder(this);
				adb.setTitle(getString(R.string.disconnect));
				adb.setMessage(getString(R.string.are_you_sure));						
				adb.setPositiveButton("Ok",
						new DialogInterface.OnClickListener() {

							public void onClick(DialogInterface dialog, int which) {
								SharedPreferences preferences = getSharedPreferences("prefs", MODE_PRIVATE);
						  		preferences.edit().remove("hash").commit();
						  		startActivity(new Intent(FragmentsSliderActivity.this, LoginActivity.class));
						  		mController.setHash(null);
						  		mController.setPlayersList(null);
						  		finish();
							}
						});
				adb.setNegativeButton("Annuler", null);
				adb.show();  				  		
		  	}
	        return true;
	    }
	
	 
	@Override
	protected void onStart() {
		super.onStart();
		this.setTitle(getString(R.string.player_ranking));
		// new intent to bind service
		Intent intent = new Intent(this, ShadowStatsController.class);
		getApplicationContext().bindService(intent, mControllerConnection, Context.BIND_AUTO_CREATE);
	}
	
	
	/**
	 * Create the fragment List, set OnPageChangeListener on them to
	 * update the actionbar when new fragment is selected
	 */
	public void initiateFragments()
	{
		// Creation of Fragment list for paging
		mFragments = new Vector<Fragment>();

		// Adding Fragments into the list
		mFragments.add(Fragment.instantiate(this,TeamStatsFragment.class.getName()));
		mFragments.add(Fragment.instantiate(this,StatsFragment.class.getName()));
		mFragments.add(Fragment.instantiate(this,GameFragment.class.getName()));

		// Adapter's creation caring about displaying fragment list
		this.mPagerAdapter = new MyPagerAdapter(super.getSupportFragmentManager(), mFragments);

		mPager = (ViewPager) super.findViewById(R.id.viewpager);
		// Affectation de l'adapter au ViewPager
		mPager.setAdapter(this.mPagerAdapter);
		
		mPager.setOnPageChangeListener(new OnPageChangeListener() {
			
			public void onPageSelected(int position) {
				if (position==0){
					FragmentsSliderActivity.this.setTitle(getString(R.string.team_ranking));
					TeamStatsFragment fragment = (TeamStatsFragment) mFragments.get(position);
					fragment.displayResults();
					invalidateOptionsMenu();
				}
				if (position==1)
				{
					FragmentsSliderActivity.this.setTitle(getString(R.string.player_ranking));
					StatsFragment fragment = (StatsFragment) mFragments.get(position);
					fragment.updateList();
					invalidateOptionsMenu();
				}
				else if (position==2)
				{
					FragmentsSliderActivity.this.setTitle(getString(R.string.new_game));
					GameFragment fragment = (GameFragment) mFragments.get(position);
					fragment.updateList();
					invalidateOptionsMenu();
				}
			}
			
			public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {}
			
			public void onPageScrollStateChanged(int state) {}
		});
		mPager.setCurrentItem(1);
	}
	
	
	/**
	 * Method refreshing playerList from the server. Error message displayed if no internet connection
	 */
	public void updatePlayerList() {
		if (Util.isOnline(this)) {
			if (mRefreshTask != null && mRefreshTask.getStatus() != Status.FINISHED) {
				mRefreshTask.cancel(true);
			}
			mRefreshTask = new PlayersListRefreshTask();
			mRefreshTask.execute();
		} else
			toastMessage(getString(R.string.connection_error));
	}
	
	
	/**
	 * Method launching server update. Error message displayed if no internet connection
	 */
	public void updateServer() {
		if (Util.isOnline(this)) {
			if (mPutTask != null && mPutTask.getStatus() != Status.FINISHED) {
				mPutTask.cancel(true);
			}
			mPutTask = new PlayersPutTask();
			mPutTask.execute();
		} else
			toastMessage(getString(R.string.connection_error));
	}

	
	/**
	 * onActivityResult
	 */
	public void onActivityResult(int requestCode, int resultCode, Intent data) {
		if ((requestCode == UPDATE_STATS_ID) && (resultCode == RESULT_OK)) {
			// a new game was added
			Bundle extras = data.getExtras();
			GameFragment fragment = (GameFragment) mFragments.get(2);
			// We get 3 extras from UpdateStatsActivity. status=0:won; status=1: lost; team=0:shadow; team=1:hunter; team=2:neutral

			if (extras != null && extras.containsKey("gameStatus")) {
				int status = extras.getInt("gameStatus");
				int team = extras.getInt("team");
				int position;
				for (position = 0; position < fragment.getCheckedState().length; position++) {
					if (fragment.getCheckedState()[position] == true) {
						switch (team) {
						case 0:
							if (status == 0){
								mController.getPlayersList().getPlayers().get(position).incrementWS();
								mController.getTeamList().getTeam(TeamType.SHADOW).incrementWin();
							}
							else{
								mController.getPlayersList().getPlayers().get(position).incrementLS();
								mController.getTeamList().getTeam(TeamType.SHADOW).incrementLost();
							}
							break;

						case 1:
							if (status == 0){
								mController.getPlayersList().getPlayers().get(position).incrementWH();
								mController.getTeamList().getTeam(TeamType.SHADOW).incrementWin();
							}
							else{
								mController.getPlayersList().getPlayers().get(position).incrementLH();
								mController.getTeamList().getTeam(TeamType.SHADOW).incrementLost();
							}
							break;

						case 2:
							if (status == 0){
								mController.getPlayersList().getPlayers().get(position).incrementWN();
								mController.getTeamList().getTeam(TeamType.SHADOW).incrementWin();
							}
							else{
								mController.getPlayersList().getPlayers().get(position).incrementLN();
								mController.getTeamList().getTeam(TeamType.SHADOW).incrementLost();
							}
							break;
						default:
							break;
						}
					}
				}
				
				fragment.updateList();
				updateServer();
			}
		}
		
		else if ((requestCode == NEW_PLAYER_ID) && (resultCode == RESULT_OK)) {
			// a new player was created 
			Bundle extras = data.getExtras();

			if (extras != null && extras.containsKey("player")) {
				String player = extras.getString("player");
				mapPlayer(player);	
				StatsFragment fragment = (StatsFragment) mFragments.get(1);
				fragment.updateList();
			}
			updateServer();
		}	
	}
	
	/**
	 * Deletes player
	 * @param position player to delete
	 */
	public void deletePlayer(int position){
		StatsFragment fragment = (StatsFragment) mFragments.get(1);
		mController.getPlayersList().getPlayers().remove(position);			
		fragment.updateList();
		updateServer();
	}
	
	/**
	 * inits player
	 * @param position
	 */
	public void initPlayer(int position){
		StatsFragment fragment = (StatsFragment) mFragments.get(1);
		mController.getPlayersList().getPlayers().get(position).reInit();			
		fragment.updateList();
		updateServer();
	}
	
	/**
	 * Builds a player type with a string
	 * 
	 * @param strPlayer
	 */
	private void mapPlayer(String strPlayer) {
		Player player = null;
		try {
			player = mMapper.readValue(strPlayer, Player.class);
			mController.getPlayersList().getPlayers().add(player);
		} catch (JsonParseException e) {
			e.printStackTrace();
		} catch (JsonMappingException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	
	/**
	 * AsyncTask making HTTP Put request in a second thread. Updating server data
	 * 
	 * @author Arnaud
	 * 
	 */
	private class PlayersPutTask extends AsyncTask<Void, Void, String> {

		String error=null;
		@Override
		protected String doInBackground(Void... params) {

			String url = getString(R.string.web_app_url)+ getString(R.string.updatestats);
			String response = null;
			Http request = new Http();

			try {
				//Creation of a pair Key/Value to put on the server and get response.
				String s = mMapper.writeValueAsString(mController.getPlayersList());
				String s2= mMapper.writeValueAsString(mController.getTeamList());
				
				ArrayList<NameValuePair> pairs = new ArrayList<NameValuePair>();
				pairs.add(new BasicNameValuePair("playerList", s));
				pairs.add(new BasicNameValuePair("teamList", s2));
				response = request.executePutRequest(url, pairs, mController.getHash());

			} catch (JsonParseException e) {
				error=e.toString();
			} catch (JsonMappingException e) {
				error=e.toString();
			} catch (IllegalStateException e) {
				error=e.toString();
			} catch (IOException e) {
				error=e.toString();
			} catch (ServerErrorException e) {
				error=e.toString();
			}
			return response;
		}

		@Override
		protected void onPostExecute(String result) {
			super.onPostExecute(result);
			if (error==null)
				if (mPager.getCurrentItem()==1)
				{
					StatsFragment fragment = (StatsFragment) mFragments.get(1);
					fragment.updateList();
				}
				else if (mPager.getCurrentItem()==2)
				{
					GameFragment fragment = (GameFragment) mFragments.get(2);
					fragment.updateList();
				}
					
			else
				displayErrorMessage(error);
		}
	};
	
	
	/**
	 * AsyncTask making HTTP Get request (second thread)
	 * 
	 * @author Arnaud
	 * 
	 */
	private class PlayersListRefreshTask extends AsyncTask<Void, Void, LoginResponseMessage> {

		String error=null;
		
		@Override
		protected void onPreExecute()
		{
			setSupportProgressBarIndeterminateVisibility(true);
		}
		
		@Override
		protected LoginResponseMessage doInBackground(Void... params) {

			LoginResponseMessage responseMessage = null;
			ObjectMapper jacksonMapper = new ObjectMapper();
			/** PlayersListRequest */
			Http getRequest = new Http();
			String url = getString(R.string.web_app_url) + getString(R.string.updatestats);
			try {
				String result= getRequest.executeGetRequest(url, mController.getHash());
				responseMessage = jacksonMapper.readValue(result, LoginResponseMessage.class);

			} catch (JsonParseException e) {
				error=e.getMessage();
			} catch (JsonMappingException e) {
				error=e.getMessage();
			} catch (IllegalStateException e) {
				error=e.getMessage();
			} catch (IOException e) {
				error=e.getMessage();
			}
			return responseMessage;
		}

		@Override
		protected void onPostExecute(LoginResponseMessage result) {
			//updating playerList
			setSupportProgressBarIndeterminateVisibility(false);
			if (error==null)
			{
				mController.setTeamList(result.getTeamList());
				mController.setPlayersList(result.getPlayerList());
				StatsFragment fragment = (StatsFragment) mFragments.get(1);
				fragment.updateList();				
			}
			else
			{
				displayErrorMessage(error);
			}
		}
	};
	
	
	/**
	 * Displaying error message in an AlertDialog
	 * @param msg message to display
	 */
	private void displayErrorMessage(String msg) {
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		builder.setTitle(getString(R.string.error));
		builder.setMessage(msg);
		builder.setPositiveButton(R.string.ok, null);
		builder.show();
	}

	 /** Displaying message in a toast
	 * @param msg message to display
	 */
	private void toastMessage(String msg) {
		Toast.makeText(getApplicationContext(), msg , Toast.LENGTH_LONG).show();

	}

	public ShadowStatsController getController() {
		return mController;
	}


	public void setController(ShadowStatsController mController) {
		this.mController = mController;
	}

	
}